package org.activequant.tradesystem.ib.selectorstrategy;

import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.activequant.core.domainmodel.InstrumentSpecification;
import org.activequant.core.domainmodel.marketscanner.MarketScan;
import org.activequant.core.domainmodel.marketscanner.MarketScanRow;
import org.activequant.core.domainmodel.marketscanner.ScanCriteria;
import org.activequant.tradesystem.ib.InstrumentStats;
import org.activequant.tradesystem.ib.MarketScannerFactory;
import org.activequant.tradesystem.ib.MarketScannerFactory.MarketScanWorker;
/**
 * An ISelectorStrategy implementation.<br/>
 * Looks at the head of the scanHistory(ConcurrentLinkedQueue&lt;MarketScan&gt;) of each MarketScanWorker in the availableScanners(Map&lt;ScanCriteria, MarketScanWorker&gt;)
 * of the given marketScanHistory(MarketScanHistory) and finds the InstrumentSpecification occurring more than once. Each of these InstrumentSpecification is paired with an InstrumentStats object containing
 * all the ScanCriteria that returned that InstrumentSpecification and adds them to the given possibleCandidates(Map&lt;InstrumentSpecification,InstrumentStats&gt;) which are then returned for chaining
 * @author Dimitar
 *
 */
public class CrossReferencingSelectorStrategy implements ISelectorStrategy{

	/**
	 * Looks at the head of the scanHistory(ConcurrentLinkedQueue&lt;MarketScan&gt;) of each MarketScanWorker in the availableScanners(Map&lt;ScanCriteria, MarketScanWorker&gt;)
	 * of the given marketScanHistory(MarketScanHistory) and finds the InstrumentSpecification occurring more than once. Each of these InstrumentSpecification is paired with an InstrumentStats object containing
	 * all the ScanCriteria that returned that InstrumentSpecification and adds them to the given possibleCandidates(Map&lt;InstrumentSpecification,InstrumentStats&gt;) which are then returned for chaining
	 */
	public Map<InstrumentSpecification,InstrumentStats> getOpportunities(MarketScannerFactory marketScanHistory, Map<InstrumentSpecification,InstrumentStats> possibleCandidates){
		Map<ScanCriteria, MarketScanWorker> availableScanners=marketScanHistory.getAvailableScanners();
		Set<InstrumentSpecification> instruments=new HashSet<InstrumentSpecification>();
		Set<InstrumentSpecification> repeating=new HashSet<InstrumentSpecification>();
		for(Entry<ScanCriteria, MarketScanWorker> entry:availableScanners.entrySet()){
			//ScanCriteria scanCriteria=entry.getKey();
			MarketScanWorker msw=entry.getValue();
			List<MarketScan> scanHistory= msw.getScanHistory();
			if(scanHistory.size()!=0){
				//Iterator<MarketScan> iterator=scanHistory.iterator();
				//while(iterator.hasNext()){
					//MarketScan ms=iterator.next();
					MarketScan ms=scanHistory.get(0);
					List<MarketScanRow> msrs= ms.getRows();
					for(MarketScanRow msr:msrs){
						InstrumentSpecification instrSpec= msr.getInstrumentSpecificationDetails().getInstrumentSpecification();
						if(!instruments.add(instrSpec)){
							repeating.add(instrSpec);
						}
					}
				//}				
			}
		}	
		for(Entry<ScanCriteria, MarketScanWorker> entry: availableScanners.entrySet()){
			ScanCriteria scanCriteria=entry.getKey();
			MarketScanWorker msw=entry.getValue();
			List<MarketScan> scanHistory= msw.getScanHistory();
			if(scanHistory.size()!=0){
				Iterator<MarketScan> iterator=scanHistory.iterator();
				while(iterator.hasNext()){
					MarketScan ms=iterator.next();
					List<MarketScanRow> msrs= ms.getRows();
//					for(MarketScanRow msr:msrs){
					for(int i=0;i<msrs.size();i++){
						MarketScanRow msr=msrs.get(i);
						InstrumentSpecification instrSpec= msr.getInstrumentSpecificationDetails().getInstrumentSpecification();
						int ranking=i;//msr.getRanking();
						if(repeating.contains(instrSpec)){
							InstrumentStats stats=possibleCandidates.get(instrSpec);
							if(stats==null){
								stats=new InstrumentStats();
							}
							stats.addMatchingCriteria(scanCriteria, ranking);														
							possibleCandidates.put(instrSpec, stats);							
						}
						//contractDetailsSource.requestInstrumentSpecificationDetails(instrSpec, listener);
					}
				}
				
			}
		}
		return possibleCandidates;
	}
}
